package mapEditor.obj;

import debug.*;

import mapEditor.MapEditor;
import mapEditor.svg.SVGDOMTree;
import mapEditor.utils.MapLocation;
import mapEditor.utils.SvgFill;
import mapEditor.utils.SvgStroke;
import mapEditor.utils.Util;

import java.awt.GridLayout;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JCheckBox;
import javax.swing.JTextField;
import javax.swing.JPanel;

import org.w3c.dom.svg.SVGPathElement;

import java.io.InputStream;
import java.io.ByteArrayInputStream;
import java.io.IOException;


public class PathObject extends DrawObject
{ //protected static final boolean USE_AnimatedLength=false; // OVERRIDE (to make updateSVGElement work)

  public PathObject(SVGDOMTree domTree,MapLocation location)
  { super(domTree,domTree.appendSVGPathElement());
    stroke.setEnabled(true);
    add(location); 
  }
  
  public PathObject(SVGDOMTree domTree,SVGPathElement svgElement)
  { super(domTree,svgElement);
	decodeSVG(svgElement);
  }
  
  public void decodeSVG(SVGPathElement svgElement)
  { Debug.TRACE("PathObject.decodeSVG: svgElement="+svgElement);
    this.setIdent(svgElement.getAttribute("id"));
    this.fill=new SvgFill(svgElement);
    this.stroke=new SvgStroke(svgElement);
    String d=svgElement.getAttribute("d");
    //Debug.TRACE("PathObject.decodeSVG: name="+name+", d="+d);
    clearPointSet();
    InputStream inputStream=new ByteArrayInputStream(d.getBytes());
    try
    { while(inputStream.available()>0)
      { int c=inputStream.read();
        //Debug.TRACE("PathObject.decodeSVG: c="+(char)c);
        if(c=='M' || c=='L') 
        { double x=readNumber(inputStream);
          inputStream.read(); // Skip ','
          double y=readNumber(inputStream);	
          add(MapLocation.newPixelPoint(domTree.getMapGrid(),x,y));
        }
        else if(c=='Z') setClosedPath(true);	
      }
    } catch(IOException e) { Debug.EXCEPTION("PathObject.decodeSVG",e); }
  }
  
  protected void directUpdateSVGElement()
  {	svgElement.setAttributeNS(null,"id",getIdent());
    svgElement.setAttributeNS(null,"d",getD());
    fill.appendSVGAttributes(svgElement);
    stroke.appendSVGAttributes(svgElement);
  }
  
  private String getD()
  { // E.G.  M263.0,248.0L450.0,235.0L265.0,358.0L264.0,246.0
	int n=numberOfPoints(); if(n<2) return("");
	MapLocation p0=getMapLocation(0);
    StringBuffer d=new StringBuffer();
    d.append("M").append(p0.getMapPixelX()).append(',').append(p0.getMapPixelY());
    for(int i=1;i<n;i++)
    { MapLocation p=getMapLocation(i);
      d.append('L').append(p.getMapPixelX()).append(',').append(p.getMapPixelY());
    }
    if(getClosedPath()) d.append('Z');  
	return(d.toString());  
  }

  private double readNumber(InputStream inputStream) throws IOException
  { StringBuffer buf=new StringBuffer();
	WHILE:while(true)
	{ inputStream.mark(2);
	  int c=inputStream.read();
	  if(Character.isDigit(c) || c=='.') buf.append((char)c);
	  else break WHILE;
	}
	inputStream.reset();
	String num=buf.toString();
	double val=Double.parseDouble(num);
	return(val);
  }

//  // SEE: http://www.antigrain.com/research/bezier_interpolation/index.html
//  // SEE: http://en.wikipedia.org/wiki/Bezier_curve
//  public void paint1(Graphics2D g,MapViewer mapNavigator)
//  { int n=pointSet.size(); if(n<2) return;
//    UTM32.MapPixelPoint p0=getPixelPoint(0);
//    GeneralPath path=new GeneralPath();
//    path.moveTo(p0.getX(),p0.getY());
//    for(int i=1;i<n;i++)
//    { UTM32.MapPixelPoint prev=getPixelPoint(i-1);
//      UTM32.MapPixelPoint p=getPixelPoint(i);
//      UTM32.MapPixelPoint suc=(i==n-1)?p:getPixelPoint(i);
//      Point2D c=controlP(prev,p,suc);
//      path.quadTo(c.getX(),c.getY(),p.getX(),p.getY());
//    }
//	g.draw(path);  
//	g.setColor(Color.red);
//	paint1(g,mapNavigator);
//	g.setColor(Color.black);
//  }
//  
//  private Point2D controlP(Point2D prev,Point2D p,Point2D suc)
//  { double dx=suc.getX()-prev.getX();
//	double dy=suc.getY()-prev.getY(); 
//	return(new Point2D.Double(p.getX()+dx,p.getY()+dy));
//  }
  
  
  private void ensureParallelogram()
  { if(this.numberOfPoints()==4)
    { MapLocation p0=getMapLocation(0);
      MapLocation p1=getMapLocation(1);
      MapLocation p2=getMapLocation(2);
      MapLocation p3=getMapLocation(3);
      double dx=p1.getX()-p0.getX();
      double dy=p1.getY()-p0.getY();
      p3.setX(p2.getX()-dx);
      p3.setY(p2.getY()-dy);
    }
  }
  
  private void ensureRectangle()
  { if(numberOfPoints()==4)
    { MapLocation p0=getMapLocation(0);
      MapLocation p1=getMapLocation(1);
      MapLocation p2=getMapLocation(2);
      double dx=p1.getX()-p0.getX();
      double dy=p1.getY()-p0.getY();
      double a=p2.getY()-p1.getY();      
      double b=dy/dx*a;
      p2.setX(p1.getX()-b);
      ensureParallelogram();
    }
  }


  // ****************************************************************
  // *** INNER CLASS: EditGeneralPanel
  // ****************************************************************
  public JPanel getEditGeneralPanel(String title)
  { return(new EditGeneralPanel(title)); }
  private class EditGeneralPanel extends JPanel
  { static final long serialVersionUID=0; // AD'HOC
    private JTextField identField;
    private JButton strokeButton;
    private JButton fillButton;
      
    public void paint(Graphics g)
    { Debug.TRACE("PathObject.EditGeneralPanel.paint: ");
      identField.setText(getIdent());
      strokeButton.setBackground(stroke.getColor());
      fillButton.setBackground(fill.getColor());
  	  super.paint(g);  
    }
    	
    public EditGeneralPanel(String title)
    { setBorder(Util.getTitleBorder(title));
      if(numberOfPoints()==4) // Firkant
      { setPreferredSize(new Dimension(350,120));//140));
        setLayout(new GridLayout(6,2));
      }
      else
      { setPreferredSize(new Dimension(350,120));
        setLayout(new GridLayout(5,2));
      }
      add(new JLabel("       Ident:"));
      identField=new JTextField(getIdent());
      identField.addActionListener(new ActionListener()
      { public void actionPerformed(ActionEvent e)
        { setIdent(identField.getText()); }
      });
      add(identField);
      fillButton=addEditFillButton(this,true);
      strokeButton=addEditStrokeButton(this,true);
        
      JCheckBox closedBox=new JCheckBox("Closed Path",null,getClosedPath());
      closedBox.addActionListener(new ActionListener()
      { public void actionPerformed(ActionEvent e)
        { setClosedPath(!getClosedPath());
 	      MapEditor.repaint();        	
        }
      });
      add(closedBox);
      add(new JLabel(" ")); // Space only
      
      if(numberOfPoints()==4)
      { JButton parallelogramButton=new JButton("Adjust Parallelogram");
//      parallelogramButton.setBackground(fill.getColor());
        parallelogramButton.addActionListener(new ActionListener()
        { public void actionPerformed(ActionEvent e) { ensureParallelogram(); } });
        add(parallelogramButton);
        
        JButton rectangleButton=new JButton("Adjust Rectangle");
//      rectangleButton.setBackground(fill.getColor());
        rectangleButton.addActionListener(new ActionListener()
        { public void actionPerformed(ActionEvent e) { ensureRectangle(); } });
        add(rectangleButton);
      }
    }
  }
  
}
